﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text;

namespace Infrastructure.Utils.Helpers
{
    /// <summary>
    /// 与Theme相关的Assembly帮助类
    /// </summary>
    public static partial class AssemblyHelper
    {
        const string PublicKeyTokenString = "PublicKeyToken";

        public static Assembly GetThemeAssembly(string themeName)
        {
            string assemblyName = GetThemeAssemblyName(themeName);
            Assembly assembly = AssemblyHelper.GetLoadedAssembly(assemblyName);
            if (assembly != null)
                return assembly;
            return LoadDXAssembly(assemblyName);
        }

        public static string GetThemeAssemblyFullName(string themeName)
        {
            return GetThemeAssemblyName(themeName) + GetFullNameAppendix();
        }

        public static string GetThemeAssemblyName(string themeName)
        {
            return AssemblyInfo.SRAssemblyToolkitPrefix + AssemblyInfo.ThemePrefix + themeName.Split(';').First() + AssemblyInfo.VSuffix;
        }

        public static Assembly LoadDXAssembly(string assemblyName)
        {
            Assembly assembly = null;
            try
            {
                assembly = Assembly.Load(assemblyName + GetFullNameAppendix());
            }
            catch
            {
            }
            return assembly;
        }

        public static bool IsDXProductAssembly(Assembly assembly)
        {
            return NameContains(assembly, AssemblyInfo.SRAssemblyXpfPrefix) && !IsDXThemeAssembly(assembly);
        }
        public static bool IsDXProductAssembly(string assemblyFullName)
        {
            return NameContains(assemblyFullName, AssemblyInfo.SRAssemblyXpfPrefix) && !IsDXThemeAssembly(assemblyFullName);
        }
        public static bool IsDXThemeAssembly(Assembly assembly)
        {
            return NameContains(assembly, AssemblyInfo.ThemePrefixWithoutSeparator);
        }
        public static bool IsDXThemeAssembly(string assemblyName)
        {
            return NameContains(assemblyName, AssemblyInfo.ThemePrefixWithoutSeparator);
        }


        public static ResourceSet GetResources(Assembly assembly)
        {
            string baseName = GetPartialName(assembly) + ".g";
            ResourceManager resourceManager = new ResourceManager(baseName, assembly);
            return resourceManager.GetResourceSet(System.Globalization.CultureInfo.InvariantCulture, true, false);
        }
        public static IDictionaryEnumerator GetResourcesEnumerator(Assembly assembly)
        {
            ResourceSet rs = GetResources(assembly);
            return rs == null ? null : rs.GetEnumerator();
        }
        public static Uri GetResourceUri(Assembly assembly, string path)
        {
            return new Uri(string.Format("{0}/{1};component/{2}", "pack://application:,,,", AssemblyHelper.GetPartialName(assembly), path));
        }

        public static Stream GetResourceStream(Assembly assembly, string path, bool pathIsFull)
        {
            path = path.ToLowerInvariant();
            Stream stream = GetResourceStreamCore(assembly, path, pathIsFull);
            if (stream == null)
            {
                stream = GetResourceStreamCore(assembly, path + ".zip", pathIsFull);
                if (stream != null)
                    stream = new GZipStream(stream, CompressionMode.Decompress);
            }
            return stream;
        }
        public static Stream GetEmbeddedResourceStream(Assembly assembly, string name, bool nameIsFull)
        {
            name = name.Replace('/', '.');
            Stream stream = GetEmbeddedResourceStreamCore(assembly, name, nameIsFull);
            if (stream == null)
            {
                stream = GetEmbeddedResourceStreamCore(assembly, name + ".zip", nameIsFull);
                if (stream != null)
                    stream = new GZipStream(stream, CompressionMode.Decompress);
            }
            return stream;
        }
        static Stream GetResourceStreamCore(Assembly assembly, string path, bool pathIsFull)
        {
            if (pathIsFull)
            {
                ResourceSet resources = GetResources(assembly);
                if (resources == null) return null;
                return resources.GetObject(path, false) as Stream;
            }
            else
            {
                IDictionaryEnumerator enumerator = GetResourcesEnumerator(assembly);
                if (enumerator == null) return null;
                while (enumerator.MoveNext())
                {
                    string resourceName = (string)enumerator.Key;
                    if (resourceName == path || resourceName.EndsWith("/" + path, StringComparison.Ordinal))
                        return enumerator.Value as Stream;
                }
                return null;
            }
        }
        static Stream GetEmbeddedResourceStreamCore(Assembly assembly, string name, bool nameIsFull)
        {
            string nameSpace = GetDefultNamespace(assembly);
            string fullName = nameSpace + name;
            Stream stream = assembly.GetManifestResourceStream(fullName);
            if (stream != null || nameIsFull) return stream;
            foreach (string resourceName in assembly.GetManifestResourceNames())
            {
                if (resourceName.EndsWith("." + name, StringComparison.Ordinal))
                    return assembly.GetManifestResourceStream(resourceName);
            }
            return null;
        }
        #region
        public static string GetShortNameWithoutVersion(Assembly assembly)
        {
            return GetShortNameWithoutVersion(assembly.FullName);
        }
        public static string GetShortNameWithoutVersion(string fullName)
        {
            string name = fullName.Split(',')[0];
            string nameWithoutVSuffix = name.Replace(AssemblyInfo.VSuffix, string.Empty);
            return nameWithoutVSuffix;
        }

        public static string GetFullNameAppendix()
        {
            return ", Version=" + AssemblyInfo.Version + ", Culture=neutral, " + PublicKeyTokenString + "=" + GetCoreAssemblyPublicKeyToken();
        }

        public static string GetCoreAssemblyPublicKeyToken()
        {
            string coreAssemblyName = GetDXAssemblyFullName();
            int publicKeyTokenIndex = coreAssemblyName.IndexOf(PublicKeyTokenString, StringComparison.Ordinal);
            int publicKeyTokenLenght = "31bf3856ad364e35".Length;
            return typeof(AssemblyHelper).Assembly.FullName.Substring(publicKeyTokenIndex + (PublicKeyTokenString + "=").Length, publicKeyTokenLenght);
        }

        static string GetDXAssemblyFullName()
        {
            Assembly assemblyHelperAssembly = typeof(AssemblyHelper).Assembly;
            string assemblyFullName = assemblyHelperAssembly.FullName;
            if (NameContains(Assembly.GetExecutingAssembly().FullName, AssemblyInfo.SRAssemblyData)) return assemblyFullName;
            if (NameContains(Assembly.GetExecutingAssembly().FullName, AssemblyInfo.SRAssemblyDemoDataCore)) return assemblyFullName;
            if (NameContains(Assembly.GetExecutingAssembly().FullName, AssemblyInfo.SRAssemblyXpfMvvm)) return assemblyFullName;
            throw new NotSupportedException(string.Format("Wrong DX assembly: {0}", assemblyFullName));
        }
        #endregion
    }
}
